package cn.lg.soar.generator.service.impl;

import cn.lg.soar.common.data.dict.DictItem;
import cn.lg.soar.common.model.PageQuery;
import cn.lg.soar.common.model.PageResult;
import cn.lg.soar.common.util.AssertUtil;
import cn.lg.soar.common.util.FormatUtils;
import cn.lg.soar.common.util.data.DataUtil;
import cn.lg.soar.common.util.data.StringUtil;
import cn.lg.soar.generator.entity.DataSource;
import cn.lg.soar.generator.mapper.DataSourceMapper;
import cn.lg.soar.generator.model.ColumnInfo;
import cn.lg.soar.generator.model.GenConfig;
import cn.lg.soar.generator.model.TableInfo;
import cn.lg.soar.generator.util.Utils;
import com.alibaba.druid.pool.DruidDataSource;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author luguoxiang
 * 开源项目：https://gitee.com/lgx1992/lg-soar 求star！请给我star！请帮我点个star！
 */
@Service
public class TableService {

    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Autowired
    private DataSourceMapper dataSourceMapper;

    private RowMapper<ColumnInfo> rowMapper = (rs, i) -> {
        ColumnInfo s = new ColumnInfo();
        s.setName(rs.getString("COLUMN_NAME"));
        s.setPropertyName(StringUtil.underscoreToCamel(s.getName()));
        s.setComment(rs.getString("COLUMN_COMMENT"));
        s.setNullable("YES".equals(rs.getString("IS_NULLABLE")));
        s.setPk("PRI".equals(rs.getString("COLUMN_KEY")));
        s.setType(rs.getString("DATA_TYPE"));
        List<String> args = new ArrayList<>(2);
        String length = rs.getString("CHARACTER_MAXIMUM_LENGTH");
        String precision = rs.getString("NUMERIC_PRECISION");
        String scale = rs.getString("NUMERIC_SCALE");
        if (length != null) {
            args.add(length);
        }
        if (precision != null) {
            args.add(precision);
        }
        if (scale != null) {
            args.add(scale);
        }
        s.setArgs(args.isEmpty() ? null : args);
        return s;
    };

    private RowMapper<TableInfo> tableMapper = (rs, i) -> {
        TableInfo info = new TableInfo();
        info.setName(rs.getString("TABLE_NAME"));
        info.setComment(rs.getString("TABLE_COMMENT"));
        return info;
    };

    public List<DictItem<String>> dbList() {
        List<DictItem<String>> list = dataSourceMapper.selectList(
                Wrappers.<DataSource>lambdaQuery()
                        .select(DataSource::getId, DataSource::getName)
                        .eq(DataSource::getDisabled, false)
        ).stream().map(x -> {
            DictItem<String> item = new DictItem<>();
            item.setValue(x.getId());
            item.setLabel(x.getName());
            return item;
        }).collect(Collectors.toList());
        DictItem<String> def = new DictItem<>();
        def.setValue("");
        def.setLabel("默认数据源");
        list.add(0, def);
        return list;
    }

    public PageResult<Map<String, Object>> getTableList(String dataSourceId, String tableName, PageQuery pageQuery){
        if(StringUtil.isBlank(tableName)){
            tableName = "";
        }
        Long total = getJdbcTemplate(dataSourceId).queryForObject("SELECT count(1) FROM INFORMATION_SCHEMA. TABLES WHERE table_schema = DATABASE() and TABLE_NAME like ?",
                Long.class, "%" + tableName + "%");

        List<Map<String, Object>> list = getJdbcTemplate(dataSourceId).queryForList("SELECT TABLE_NAME, TABLE_COMMENT FROM INFORMATION_SCHEMA. TABLES WHERE table_schema = DATABASE() and TABLE_NAME like ? LIMIT ?,?",
                "%" + tableName + "%", (pageQuery.getPageNo() - 1) * pageQuery.getPageSize(), pageQuery.getPageSize());

        PageResult<Map<String, Object>> pagination = new PageResult<>(total, list);
        pagination.setPageNo(pageQuery.getPageNo());
        pagination.setPageSize(pageQuery.getPageSize());

        return pagination;
    }

    public TableInfo getTableInfo(String dataSourceId, String tableName) {
        TableInfo tableInfo = getJdbcTemplate(dataSourceId).query(
                "SELECT TABLE_NAME,TABLE_COMMENT " +
                        "FROM information_schema.`TABLES` t " +
                        "WHERE t.TABLE_SCHEMA = (SELECT DATABASE()) AND t.TABLE_NAME = ?",
                tableMapper,
                tableName
        ).get(0);

        List<ColumnInfo> columnInfos = getJdbcTemplate(dataSourceId).query("SELECT " +
                "t.COLUMN_NAME, " +
                "t.DATA_TYPE, " +
                "t.CHARACTER_MAXIMUM_LENGTH, " +
                "t.NUMERIC_PRECISION, " +
                "t.NUMERIC_SCALE, " +
                "t.COLUMN_COMMENT, " +
                "t.COLUMN_KEY, " +
                "t.IS_NULLABLE " +
                "FROM information_schema.`COLUMNS` t " +
                "WHERE t.TABLE_SCHEMA = (SELECT DATABASE()) AND t.TABLE_NAME = ?", rowMapper, tableName);
        tableInfo.setColumnInfos(columnInfos);
        return tableInfo;
    }

    public GenConfig genConfig(String dataSourceId, String tableName){
        return Utils.genConfig(
                getTableInfo(dataSourceId, tableName)
        );
    }

    private JdbcTemplate getJdbcTemplate(String dataSourceId) {
        if (DataUtil.isValuable(dataSourceId)) {
            DataSource dataSource = dataSourceMapper.selectById(dataSourceId);
            AssertUtil.notNull(dataSource, "数据源不存在");
            DruidDataSource druidDataSource = new DruidDataSource();
            druidDataSource.setUrl(dataSource.getUrl());
            druidDataSource.setUsername(dataSource.getUsername());
            druidDataSource.setPassword(dataSource.getPassword());
            druidDataSource.setDriverClassName(dataSource.getDriverClassName());
            return new JdbcTemplate(druidDataSource);
        }
        return jdbcTemplate;
    }
}